/**
 * 使用类似es5的语法定义一个Promise模块
 */

//es5使用立即执行函数定义模块

(function(window){ 

    var PENDING = 'pending'
    var RESOLVED = 'resolved'
    var REJECTED = 'rejected'

    function Promise(executor){
        this.status = PENDING
        this.data = undefined
        var self = this
        this.callback = undefined
        function resolve(data){
            if(self.status!==PENDING) return
            self.status = RESOLVED
            self.data = data

            //异步执行then指定的回调函数,     如果then在异步任务结束之前 
            if(typeof self.callback !=='undefined'){
                //通过timeout 0 实现异步执行
                setTimeout(()=>{ 
                    self.callback.onResolved(self.data)
                })
            }
            
        }
        function reject(reason){
            if(self.status!==PENDING) return
            self.status = REJECTED
            self.data = reason

            if(typeof self.callback !=='undefined'){
                setTimeout(()=>{
                    self.callback.onRejected(self.data)
                })
            }
        }

        //抛出异常的时候会返回一个rejected的Promise对象
        try{
            executor(resolve,reject)
        }catch(e){
            reject(e)
        }
    }   

    Promise.prototype.then = function(onResolved,onRejected){

        //两个回调参数如果没有指定的话，默认就把数据、失败原因向下传递
        if(typeof onResolved !=='function') onResolved = data=>data
        if(typeof onRejected !=='function') onRejected = reason=>reason

        var self = this

        function handler(callback,resolve,reject){
            try{
                var ans = callback(self.data)
                if(ans instanceof Promise){
                    ans.then(
                        data=>resolve(data),
                        reason=>reject(reason)
                    )
                }else{
                    resolve(ans)
                }
            }catch(e){
                reject(e)
            }
        }

        //then要返回一个已经resolved的Promise
        //返回的Promise的状态要根据then传入的回调函数来决定，可能直接结束，也可能继续执行异步任务
        return new Promise((resolve,reject)=>{
            if(self.status===PENDING){
                self.callback={
                    onResolved(){
                        handler(onResolved,resolve,reject)
                    },
                    onRejected(){
                        handler(onRejected,resolve,reject)
                    }
                }
            }else if (self.status===RESOLVED){
                setTimeout(()=>{
                    handler(onResolved,resolve,reject)
                })
            }else{
                setTimeout(()=>{
                    handler(onRejected,resolve,reject)
                })
            }
        })
        
        
    }
    
    Promise.prototype.catch = function(onRejected){
        return this.then(undefined,onRejected)
    }

    //自己理解写的
    //resolve分3种参数
    // Promise.resolve = function(value){
    //     if(value instanceof Promise) return value
    //     if(value!=undefined&&value.then!=null)return new Promise(value.then)
    //     return new Promise(resolve=>resolve(value))
    // }

    //用途就是将value转换成Promise
    Promise.resolve = function (value) {
        // 返回一个成功/失败的promise
        return new Promise((resolve, reject) => {
          // value是promise
          if (value instanceof Promise) { // 使用value的结果作为promise的结果
            value.then(resolve, reject)
          } else { // value不是promise  => promise变为成功, 数据是value
            resolve(value)
          }
        })
      }

    Promise.reject = function(reason){
        return new Promise((_,reject)=> reject(reason))
    }



    Promise.all = function (promises) {
        if(promises.length==0) return new Promise.resolve([])
        let v = new Array(promises.length)
        let cnt = 0
        return new Promise((resolve,reject)=>{
            for(let i=0;i<promises.length;i++){
                //统一转换成Promise
                const cur = Promise.resolve(promises[i])
                cur.then(data=>{
                    v[i] = data
                    cnt++
                    if(cnt==promises.length){
                        resolve(v)
                    }
                }).catch(reason=>{
                    reject(reason)
                })
            }
        })    
    }



    Promise.race = function(promises) {
        return new Promise((resolve,reject)=>{
            for(let v of promises){
                if(v instanceof Promise){
                    v.then(data=>resolve(data),reason=>reject(reason))
                }else{
                    //必须设置成异步的，否则可能导致前面的resolved没有更高的优先级
                    setTimeout(()=>resolve(v))
                    break
                }

                //直接resolve没有异步14,导致resolve14就错了
                // Promise.resolve(v).then(data=>resolve(data),reason=>reject(reason))
            }
                
        })
        
    }

    window.Promise = Promise
}
)(window)


//测试race
// const t = new Promise(resolve=>{
//     setTimeout(()=>{
//         resolve(1)
//     })
// })
// const tt = new Promise(resolve=>resolve(12))
// Promise.race([t,tt,14])

//测试all
const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(99999)
    },15)
})
p.then(data=>{
    console.log(data)
}).catch(reason=>{
    console.error(reason)
})
const pall = Promise.all([1,2,p,4,43])